#include <algorithm>

#include "BVH.h"

CBVHNode::CBVHNode(std::vector<shared_ptr<CHittable>>& vObjects, size_t vStart, size_t vEnd)
{
	m_BBox = CAABB::EMPTY;
	for (size_t i = vStart; i < vEnd; i++)
		m_BBox = CAABB(m_BBox, vObjects[i]->boundingBox());

	int SegAxis = m_BBox.longestAxis();

	auto Comparator = (SegAxis == 0) ? __xCompare : (SegAxis == 1) ? __yCompare : __zCompare;

	size_t ObjectScan = vEnd - vStart;

	if (ObjectScan == 1)
		m_Left = m_Right = vObjects[vStart];
	else if (ObjectScan == 2) {
		m_Left = vObjects[vStart];
		m_Right = vObjects[vStart + 1];
	}
	else {
		std::sort(std::begin(vObjects) + vStart, std::begin(vObjects) + vEnd, Comparator);

		auto Mid = vStart + ObjectScan / 2;
		m_Left = make_shared<CBVHNode>(vObjects, vStart, Mid);
		m_Right = make_shared<CBVHNode>(vObjects, Mid, vEnd);
	}

	m_BBox = CAABB(m_Left->boundingBox(), m_Right->boundingBox());
}

bool CBVHNode::hit(const CRay& vR, CInterval vRayT, CHitRecord& vHitRecord) const
{
	if (!m_BBox.hit(vR, vRayT)) return false;

	bool HitLeft = m_Left->hit(vR, vRayT, vHitRecord);
	bool HitRight = m_Right->hit(vR, CInterval(vRayT.m_Min, HitLeft ? vHitRecord.m_t : vRayT.m_Max), vHitRecord);

	return HitLeft || HitRight;

}

bool CBVHNode::__boxCompare(const shared_ptr<CHittable> vA, const shared_ptr<CHittable> vB, int AxisIndex)
{
	auto AxisIntervalA = vA->boundingBox().axisInterval(AxisIndex);
	auto AxisIntervalB = vB->boundingBox().axisInterval(AxisIndex);
	return AxisIntervalA.m_Min < AxisIntervalB.m_Min;
}